home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d11 / ooze.arc / OOZE.C < prev    next >
C/C++ Source or Header  |  1991-08-12  |  12KB  |  386 lines

  1. /* This program is sort of a lava-lamp for your computer. It requires
  2.    VGA equipment or anything else that is compatible with mode 13h of
  3.    the VGA (320x200x256 mode). To run the program, execute the command
  4.  
  5.      ooze
  6.  
  7.    The first time this is run, it will generate a random, amorphous
  8.    image on the screen and will store this image into the file ooze.ooz.
  9.    The image on the screen will then begin to "ooze" all over the
  10.    screen. To change the direction of oozing, press a key (like the
  11.    space bar). To stop the program and return to DOS, press the Escape
  12.    key.
  13.  
  14.    The next time ooze is run, it will read the file ooze.ooz and
  15.    proceede directly to ooze the image stored there. Ooze.ooz is mearly
  16.    the default filename. Any other filename may be specified on the
  17.    command line. If, for instance, the command
  18.  
  19.      ooze image1.ooz
  20.  
  21.    is issued, the file image1.ooz will be read from disk (if it is
  22.    present) and the image from this file will be oozed. If image1.ooze
  23.    is not found, it will be created in the same manner as ooze.ooz was
  24.    created above. But the image created will be different for every new
  25.    ooze image file created. You could build a whole library of differnet
  26.    ooze files!
  27.  
  28.    ---------------------- For Programmers Only -------------------------
  29.  
  30.    This program was translated to Turbo C from Turbo Pascal. The
  31.    original TP code was written and copyrighted (1988) by Bret Bulvey
  32.    [71330,3567] and can be found in various places as PLASMA.ARC (or
  33.    .ZIP depending on where you get it). The translation to TC was done
  34.    by me (Jeff Clough [71330,2227]) and includes improvements and
  35.    enhancements over the TP code. These include the elimination of
  36.    flicker, the use of secondary as well as primary colors in the color
  37.    palette, the use of 252 colors instead of only the 191 colors used in
  38.    PLASMA, the ability to reverse the direction in which the colors move
  39.    on the screen while the program is executing, and being able to
  40.    specify the name of the image file to use on the command line. Also,
  41.    as a side-effect of the process by which flicker is avoided, OOZE
  42.    should run at the same speed on all VGA equipment regardless of the
  43.    speed of the computer. The only unique part of the original code
  44.    presented here (aside from a few variable and type names) is the
  45.    algorithm for generating the amorphous images. The algorithm has been
  46.    modified (simplified, actually) so that it includes no floating
  47.    point. The original algorithm employed the use of Manhattan distances
  48.    to determine how far apart two pixels were. The code presented here
  49.    employes its own square root function (using integer bisection) and
  50.    uses this to take advantage of a little trick Pathagorus demonstrated
  51.    a while back. It is hoped that this new method for computing
  52.    distances will produce more rounded edges in the generated images.
  53.    Also, there was provision in the original code for adjusting the
  54.    "roughness of the image" at compile time. This has been removed
  55.    (since it involved a floating point operation).
  56.  
  57.    To eliminate the flicker, it was necessary to implement parts of the
  58.    program in assembly language. The code that follows is, therefore, a
  59.    hybrid of Turbo C and Assembly. Turbo C 2.0 and TASM were used to
  60.    compile/assemble this program. To recompile, do
  61.  
  62.      tcc -B -mc ooze
  63.  
  64.    This will cause TC to "compile" to assembly source code and then
  65.    invoke TASM on that code. The -mc switch may optionally be changed to
  66.    -ml or -mh for the large or huge memory models, but may not be
  67.    changed to -mt, -ms, or -mm because the tiny, small, and medium
  68.    memory models all use near data segments. The far data segments used
  69.    by the other memory models are necessary because this program uses
  70.    the fread and fwrite functions to read from and write to the video
  71.    memory directly.
  72.  
  73.    If the identifier "dotest" is defined during compilation, a test
  74.    pattern will be generated instead of the more usual amorphous images
  75.    when the program is run. This test code was used during debugging to
  76.    ensure that all colors were being represented on the screen. If you
  77.    change any part of this source code, you may want to use this test
  78.    pattern to verify that your changes meet your expectations of them.
  79.    To tell the compiler to generate the test code, include the -Ddotest
  80.    command line switch when you compile as follows:
  81.  
  82.      tcc -B -mc -Ddotest ooze
  83.  
  84.    When ooze.exe is run, the test pattern will be generated and stored
  85.    into whatever file is passed to it on the command line or to ooze.ooz
  86.    by default. Don't forget to recompile without the -Ddotest switch so
  87.    that the program will once again generate amorphous images.
  88. */
  89.  
  90. #if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
  91. #error COMPILE WITH LARGE DATA MODEL.
  92. #endif
  93.  
  94. #include <bios.h>
  95. #include <dos.h>
  96. #include <stdio.h>
  97. #include <stdlib.h>
  98. #include <string.h>
  99.  
  100. #define VERSION "1.1"
  101.  
  102. typedef struct
  103. {unsigned char r,g,b;
  104. } colortype;
  105.  
  106. colortype p[256];
  107.  
  108. int direction=0; /* controls the direction of palette rotation */
  109.  
  110. void adjust(int x1,int y1,int x,int y,int x2,int y2);
  111. int getpixel(int x,int y);
  112. void putpixel(int x,int y,int c);
  113. void rotatepalette(colortype p[]);
  114. void setvgapalette(void *buffer,int first,int length);
  115. void subdivide(int x1,int y1,int x2,int y2);
  116. unsigned sqrt(long n);
  117. void test(void);
  118. void usage(void);
  119.  
  120. int main(int argc,char *argv[])
  121. {FILE *file;
  122.  char filename[129];
  123.  union REGS reg;
  124.  unsigned char r,g,b;
  125.  int i,       /* holds the number of the current palette register */
  126.      key,     /* holds the scancode of the last key pressed       */
  127.      newooze; /* TRUE if a new .OOZ file is to be created         */
  128.  
  129.  newooze=0;
  130.  if (argc>2)
  131.   {usage();
  132.    return 1;
  133.   }
  134.  if (argc>1)
  135.   {if (stricmp(argv[1],"?")==0 ||
  136.        stricmp(argv[1],"-H")==0 ||
  137.        stricmp(argv[1],"/H")==0)
  138.     {usage();
  139.      return 1;
  140.     }
  141.    strcpy(filename,argv[1]);
  142.   }
  143.  else
  144.    strcpy(filename,"ooze.ooz");
  145.  file=fopen(filename,"rb");
  146.  if (!file)
  147.   {file=fopen(filename,"w+b");
  148.    newooze=1;
  149.   }
  150.  if (!file)
  151.   {printf("%s cannot be found or created.\n\n",filename);
  152.    usage();
  153.    return 2;
  154.   }
  155.  
  156.  /* initialize palette register array */
  157.  r=53;
  158.  g=11;
  159.  b=53;
  160.  for(i=1;i<=42;i++) /* from magenta to red */
  161.   {p[i].r=r;
  162.    p[i].g=g;
  163.    p[i].b=b--;
  164.   }
  165.  for(;i<=84;i++) /* from red to yellow */
  166.   {p[i].r=r;
  167.    p[i].g=++g;
  168.    p[i].b=b;
  169.   }
  170.  for(;i<=126;i++) /* from yellow to green */
  171.   {p[i].r=r--;
  172.    p[i].g=g;
  173.    p[i].b=b;
  174.   }
  175.  for(;i<=168;i++) /* from green to cyan */
  176.   {p[i].r=r;
  177.    p[i].g=g;
  178.    p[i].b=++b;
  179.   }
  180.  for(;i<=210;i++) /* from cyan to blue */
  181.   {p[i].r=r;
  182.    p[i].g=g--;
  183.    p[i].b=b;
  184.   }
  185.  for(;i<=252;i++) /* from blue to magenta */
  186.   {p[i].r=++r;
  187.    p[i].g=g;
  188.    p[i].b=b;
  189.   }
  190.  
  191.  /* put VGA into mode 0x13 (320x200x256) */
  192.  reg.x.ax=0x13;
  193.  int86(0x10,®,®);
  194.  
  195.  setvgapalette(p,0,128);
  196.  setvgapalette(&p[128],128,128);
  197.  
  198.  if (newooze)
  199.   {
  200. #if defined(dotest)
  201.    test();
  202. #else
  203.    srand(peek(0x40,0x6c));
  204.    putpixel(0,0,random(252)+1);
  205.    putpixel(319,0,random(252)+1);
  206.    putpixel(319,199,random(252)+1);
  207.    putpixel(0,199,random(252)+1);
  208.    subdivide(0,0,319,199);
  209. #endif
  210.    fwrite(MK_FP(0xa000,0),1,0xfa00,file);
  211.   }
  212.  else
  213.    fread(MK_FP(0xa000,0),1,0xfa00,file);
  214.  fclose(file);
  215.  
  216.  /* rotate the palette until the [Esc] key is pressed */
  217.  do
  218.   {rotatepalette(p);
  219.    if (bioskey(1))
  220.     {key=bioskey(0)>>8;
  221.      direction=1-direction;
  222.     }
  223.   }
  224.  while(key!=1);
  225.  
  226.  /* put VGA into mode 3 (color text mode (80x25)) */
  227.  reg.x.ax=3;
  228.  int86(0x10,®,®);
  229.  
  230.  return 0;
  231. } /* end of int main(argc,argv[]) */
  232.  
  233. void adjust(int x1,int y1,int x,int y,int x2,int y2)
  234. {int c,d;
  235.  long horz,vert;
  236.  if (getpixel(x,y))
  237.    return;
  238.  horz=(long)(x2-x1);
  239.  vert=(long)(y2-y1);
  240.  d=sqrt(horz*horz+vert*vert);
  241.  if (random(2))
  242.    c=((getpixel(x1,y1)+getpixel(x2,y2))/2-random(d)) % 252;
  243.  else
  244.    c=((getpixel(x1,y1)+getpixel(x2,y2))/2+random(d)) % 252;
  245.  if (c<0)
  246.    c=-c;
  247.  else
  248.    if (!c)
  249.      c=1;
  250.  putpixel(x,y,abs(c));
  251. } /* end of adjust(x1,y1,x,y,x2,y2) */
  252.  
  253. int getpixel(int x,int y)
  254. {return(peekb(0xa000,320*y+x) & 0xff);
  255. } /* end of int getpixel(x,y) */
  256.  
  257. void putpixel(int x,int y,int c)
  258. {pokeb(0xa000,320*y+x,c);
  259. } /* end of putpixel(x,y,c) */
  260.  
  261. void rotatepalette(colortype p[])
  262. {colortype temp;
  263.  if (direction)
  264.   {memmove(&temp,p+252,sizeof(colortype));
  265.    memmove(p+2,p+1,251*sizeof(colortype));
  266.    memmove(p+1,&temp,sizeof(colortype));
  267.   }
  268.  else
  269.   {memmove(&temp,p+1,sizeof(colortype));
  270.    memmove(p+1,p+2,251*sizeof(colortype));
  271.    memmove(p+252,&temp,sizeof(colortype));
  272.   }
  273.  setvgapalette(p,0,128);
  274.  setvgapalette(p+128,128,128);
  275. } /* end of rotatepalette(p) */
  276.  
  277. void setvgapalette(void *buffer,int first,int length)
  278. {asm cli        /* Disable interrupts. */
  279.  asm mov dx,3dah
  280. setvgapalette1: /* Wait for vertical retrace to end. */
  281.  asm in al,dx
  282.  asm test al,8
  283.  asm jnz setvgapalette1
  284. setvgapalette2: /* Wait for vertical retrace to start. */
  285.  asm in al,dx
  286.  asm test al,8
  287.  asm jz setvgapalette2
  288.  /* Set the VGA palette registers. */
  289.  asm push ds
  290.  _DS=FP_SEG(buffer);
  291.  _SI=FP_OFF(buffer);
  292.  asm mov dx,3c8h   /* port address of DAC address register.                   */
  293.  asm mov ax,first  /* this is the number of first DAC register to update.     */
  294.  asm out dx,al     /* start with this DAC.                                    */
  295.  asm inc dx        /* 3c9h is the port address where the RGB info is written. */
  296.  asm mov cx,length /* this is the number of DAC registers to update.          */
  297. setdacloop:
  298.  asm mov al,[si]
  299.  asm out dx,al
  300.  asm inc si
  301.  asm mov al,[si]
  302.  asm out dx,al
  303.  asm inc si
  304.  asm mov al,[si]
  305.  asm out dx,al
  306.  asm inc si
  307.  asm loop setdacloop
  308.  asm pop ds
  309.  asm sti        /* Enable interrupts. */
  310. } /* end of setvgapalette(buffer,first,length) */
  311.  
  312. void subdivide(int x1,int y1,int x2,int y2)
  313. {int c,x,y;
  314.  if (bioskey(1))
  315.    return;
  316.  if (x2-x1<2 && y2-y1<2)
  317.    return;
  318.  x=(x1+x2)/2;
  319.  y=(y1+y2)/2;
  320.  adjust(x1,y1,x,y1,x2,y1);
  321.  adjust(x2,y1,x2,y,x2,y2);
  322.  adjust(x1,y2,x,y2,x2,y2);
  323.  adjust(x1,y1,x1,y,x1,y2);
  324.  if (getpixel(x,y)==0)
  325.   {c=(getpixel(x1,y1)+getpixel(x2,y1)+getpixel(x2,y2)+getpixel(x1,y2))/4;
  326.    if (c<1)
  327.      c=1;
  328.    else
  329.      if (c>252)
  330.        c=252;
  331.    putpixel(x,y,c);
  332.   }
  333.  subdivide(x1,y1,x,y);
  334.  subdivide(x,y1,x2,y);
  335.  subdivide(x,y,x2,y2);
  336.  subdivide(x1,y,x,y2);
  337. } /* end of subdivide(x1,y1,x2,y2) */
  338.  
  339. /* Use bisection to find the root of y=x*x-n.
  340.    Return the value of x.                     */
  341. unsigned sqrt(long n)
  342. {long xl,x,xh,y;
  343.  if (n<0)
  344.    n=-n;
  345.  xl=0L;      /* (xl,xh) is the range of y=x*x-n */
  346.  xh=46340L;
  347.  while(xl<xh-1L)
  348.   {x=(xl+xh)/2;
  349.    y=x*x;
  350.    if (y<n)
  351.      xl=x;
  352.    else
  353.      xh=x;
  354.   }
  355.  if (n-xl*xl < xh*xh-n)
  356.    return((int)xl);
  357.  else
  358.    return((int)xh);
  359. } /* end of unsigned sqrt(n) */
  360.  
  361. #if defined(dotest)
  362.  
  363. void test(void)
  364. {int x,y,c;
  365.  long h,v;
  366.  for(x=0;x<320;x++)
  367.    for(y=0;y<200;y++)
  368.     {h=(long)(160-x);
  369.      v=(long)(199-y);
  370.      c=sqrt(h*h+v*v) % 252 + 1;
  371.      putpixel(x,y,c);
  372.     }
  373. } /* end of test() */
  374.  
  375. #endif
  376.  
  377. void usage(void)
  378. {printf("OOZE version %s compiled %s\n\n"
  379.         "usage: OOZE [filename]\n"
  380.         "where filename is the name of a .OOZ file.\n\n"
  381.         "If the file does not exist, it will be created.\n"
  382.         "If it already exists, the image in it will be oozed.\n"
  383.         "If the filename parameter is not given, a default\n"
  384.         "filename of OOZE.OOZ is assumed.\n",VERSION,__DATE__);
  385. } /* end of usage() */
  386.